home *** CD-ROM | disk | FTP | other *** search
/ MacHack 2000 / MacHack 2000.toast / pc / The Hacks / MacHacksBug / Python 1.5.2c1 / Mac / Lib / buildtools.py < prev    next >
Encoding:
Python Source  |  2000-06-23  |  7.2 KB  |  291 lines

  1. """tools for BuildApplet and BuildApplication"""
  2.  
  3. import sys
  4. import os
  5. import string
  6. import imp
  7. import marshal
  8. import macfs
  9. import Res
  10. import MACFS
  11. import MacOS
  12. import macostools
  13. import EasyDialogs
  14.  
  15.  
  16. BuildError = "BuildError"
  17.  
  18. DEBUG=1
  19.  
  20.  
  21. # .pyc file (and 'PYC ' resource magic number)
  22. MAGIC = imp.get_magic()
  23.  
  24. # Template file (searched on sys.path)
  25. TEMPLATE = "PythonInterpreter"
  26.  
  27. # Specification of our resource
  28. RESTYPE = 'PYC '
  29. RESNAME = '__main__'
  30.  
  31. # A resource with this name sets the "owner" (creator) of the destination
  32. # It should also have ID=0. Either of these alone is not enough.
  33. OWNERNAME = "owner resource"
  34.  
  35. # Default applet creator code
  36. DEFAULT_APPLET_CREATOR="Pyta"
  37.  
  38. # OpenResFile mode parameters
  39. READ = 1
  40. WRITE = 2
  41.  
  42.  
  43. def findtemplate():
  44.     """Locate the applet template along sys.path"""
  45.     for p in sys.path:
  46.         template = os.path.join(p, TEMPLATE)
  47.         try:
  48.             template, d1, d2 = macfs.ResolveAliasFile(template)
  49.             break
  50.         except (macfs.error, ValueError):
  51.             continue
  52.     else:
  53.         raise BuildError, "Template %s not found on sys.path" % `TEMPLATE`
  54.     template = template.as_pathname()
  55.     return template
  56.  
  57.  
  58. def process(template, filename, output, copy_codefragment):
  59.     
  60.     if DEBUG:
  61.         progress = EasyDialogs.ProgressBar("Processing %s..."%os.path.split(filename)[1], 120)
  62.         progress.label("Compiling...")
  63.     else:
  64.         progress = None
  65.     
  66.     # Read the source and compile it
  67.     # (there's no point overwriting the destination if it has a syntax error)
  68.     
  69.     fp = open(filename)
  70.     text = fp.read()
  71.     fp.close()
  72.     try:
  73.         code = compile(text, filename, "exec")
  74.     except (SyntaxError, EOFError):
  75.         raise BuildError, "Syntax error in script %s" % `filename`
  76.     
  77.     # Set the destination file name
  78.     
  79.     if string.lower(filename[-3:]) == ".py":
  80.         destname = filename[:-3]
  81.         rsrcname = destname + '.rsrc'
  82.     else:
  83.         destname = filename + ".applet"
  84.         rsrcname = filename + '.rsrc'
  85.     
  86.     if output:
  87.         destname = output
  88.     
  89.     # Try removing the output file
  90.     try:
  91.         os.remove(destname)
  92.     except os.error:
  93.         pass
  94.     process_common(template, progress, code, rsrcname, destname, 0, copy_codefragment)
  95.     
  96.  
  97. def update(template, filename, output):
  98.     if DEBUG:
  99.         progress = EasyDialogs.ProgressBar("Updating %s..."%os.path.split(filename)[1], 120)
  100.     else:
  101.         progress = None
  102.     if not output:
  103.         output = filename + ' (updated)'
  104.     
  105.     # Try removing the output file
  106.     try:
  107.         os.remove(output)
  108.     except os.error:
  109.         pass
  110.     process_common(template, progress, None, filename, output, 1, 1)
  111.  
  112.  
  113. def process_common(template, progress, code, rsrcname, destname, is_update, copy_codefragment):
  114.     # Create FSSpecs for the various files
  115.     template_fss = macfs.FSSpec(template)
  116.     template_fss, d1, d2 = macfs.ResolveAliasFile(template_fss)
  117.     dest_fss = macfs.FSSpec(destname)
  118.     
  119.     # Copy data (not resources, yet) from the template
  120.     if DEBUG:
  121.         progress.label("Copy data fork...")
  122.         progress.set(10)
  123.     
  124.     if copy_codefragment:
  125.         tmpl = open(template, "rb")
  126.         dest = open(destname, "wb")
  127.         data = tmpl.read()
  128.         if data:
  129.             dest.write(data)
  130.         dest.close()
  131.         tmpl.close()
  132.         del dest
  133.         del tmpl
  134.     
  135.     # Open the output resource fork
  136.     
  137.     if DEBUG:
  138.         progress.label("Copy resources...")
  139.         progress.set(20)
  140.     try:
  141.         output = Res.FSpOpenResFile(dest_fss, WRITE)
  142.     except MacOS.Error:
  143.         Res.CreateResFile(destname)
  144.         output = Res.FSpOpenResFile(dest_fss, WRITE)
  145.     
  146.     # Copy the resources from the target specific resource template, if any
  147.     typesfound, ownertype = [], None
  148.     try:
  149.         input = Res.FSpOpenResFile(rsrcname, READ)
  150.     except (MacOS.Error, ValueError):
  151.         pass
  152.         if DEBUG:
  153.             progress.inc(50)
  154.     else:
  155.         if is_update:
  156.             skip_oldfile = ['cfrg']
  157.         else:
  158.             skip_oldfile = []
  159.         typesfound, ownertype = copyres(input, output, skip_oldfile, 0, progress)
  160.         Res.CloseResFile(input)
  161.     
  162.     # Check which resource-types we should not copy from the template
  163.     skiptypes = []
  164.     if 'vers' in typesfound: skiptypes.append('vers')
  165.     if 'SIZE' in typesfound: skiptypes.append('SIZE')
  166.     if 'BNDL' in typesfound: skiptypes = skiptypes + ['BNDL', 'FREF', 'icl4', 
  167.             'icl8', 'ics4', 'ics8', 'ICN#', 'ics#']
  168.     if not copy_codefragment:
  169.         skiptypes.append('cfrg')
  170. ##    skipowner = (ownertype <> None)
  171.     
  172.     # Copy the resources from the template
  173.     
  174.     input = Res.FSpOpenResFile(template_fss, READ)
  175.     dummy, tmplowner = copyres(input, output, skiptypes, 1, progress)
  176.         
  177.     Res.CloseResFile(input)
  178. ##    if ownertype == None:
  179. ##        raise BuildError, "No owner resource found in either resource file or template"
  180.     # Make sure we're manipulating the output resource file now
  181.     
  182.     Res.UseResFile(output)
  183.  
  184.     if ownertype == None:
  185.         # No owner resource in the template. We have skipped the
  186.         # Python owner resource, so we have to add our own. The relevant
  187.         # bundle stuff is already included in the interpret/applet template.
  188.         newres = Res.Resource('\0')
  189.         newres.AddResource(DEFAULT_APPLET_CREATOR, 0, "Owner resource")
  190.         ownertype = DEFAULT_APPLET_CREATOR
  191.     
  192.     if code:
  193.         # Delete any existing 'PYC ' resource named __main__
  194.         
  195.         try:
  196.             res = Res.Get1NamedResource(RESTYPE, RESNAME)
  197.             res.RemoveResource()
  198.         except Res.Error:
  199.             pass
  200.         
  201.         # Create the raw data for the resource from the code object
  202.         if DEBUG:
  203.             progress.label("Write PYC resource...")
  204.             progress.set(120)
  205.         
  206.         data = marshal.dumps(code)
  207.         del code
  208.         data = (MAGIC + '\0\0\0\0') + data
  209.         
  210.         # Create the resource and write it
  211.         
  212.         id = 0
  213.         while id < 128:
  214.             id = Res.Unique1ID(RESTYPE)
  215.         res = Res.Resource(data)
  216.         res.AddResource(RESTYPE, id, RESNAME)
  217.         attrs = res.GetResAttrs()
  218.         attrs = attrs | 0x04    # set preload
  219.         res.SetResAttrs(attrs)
  220.         res.WriteResource()
  221.         res.ReleaseResource()
  222.     
  223.     # Close the output file
  224.     
  225.     Res.CloseResFile(output)
  226.     
  227.     # Now set the creator, type and bundle bit of the destination
  228.     dest_finfo = dest_fss.GetFInfo()
  229.     dest_finfo.Creator = ownertype
  230.     dest_finfo.Type = 'APPL'
  231.     dest_finfo.Flags = dest_finfo.Flags | MACFS.kHasBundle
  232.     dest_finfo.Flags = dest_finfo.Flags & ~MACFS.kHasBeenInited
  233.     dest_fss.SetFInfo(dest_finfo)
  234.     
  235.     macostools.touched(dest_fss)
  236.     if DEBUG:
  237.         progress.label("Done.")
  238.  
  239.  
  240. # Copy resources between two resource file descriptors.
  241. # skip a resource named '__main__' or (if skipowner is set) with ID zero.
  242. # Also skip resources with a type listed in skiptypes.
  243. #
  244. def copyres(input, output, skiptypes, skipowner, progress=None):
  245.     ctor = None
  246.     alltypes = []
  247.     Res.UseResFile(input)
  248.     ntypes = Res.Count1Types()
  249.     progress_type_inc = 50/ntypes
  250.     for itype in range(1, 1+ntypes):
  251.         type = Res.Get1IndType(itype)
  252.         if type in skiptypes:
  253.             continue
  254.         alltypes.append(type)
  255.         nresources = Res.Count1Resources(type)
  256.         progress_cur_inc = progress_type_inc/nresources
  257.         for ires in range(1, 1+nresources):
  258.             res = Res.Get1IndResource(type, ires)
  259.             id, type, name = res.GetResInfo()
  260.             lcname = string.lower(name)
  261.  
  262.             if lcname == OWNERNAME and id == 0:
  263.                 if skipowner:
  264.                     continue # Skip this one
  265.                 else:
  266.                     ctor = type
  267.             size = res.size
  268.             attrs = res.GetResAttrs()
  269.             if DEBUG and progress:
  270.                 progress.label("Copy %s %d %s"%(type, id, name))
  271.                 progress.inc(progress_cur_inc)
  272.             res.LoadResource()
  273.             res.DetachResource()
  274.             Res.UseResFile(output)
  275.             try:
  276.                 res2 = Res.Get1Resource(type, id)
  277.             except MacOS.Error:
  278.                 res2 = None
  279.             if res2:
  280.                 if DEBUG and progress:
  281.                     progress.label("Overwrite %s %d %s"%(type, id, name))
  282.                 res2.RemoveResource()
  283.             res.AddResource(type, id, name)
  284.             res.WriteResource()
  285.             attrs = attrs | res.GetResAttrs()
  286.             res.SetResAttrs(attrs)
  287.             Res.UseResFile(input)
  288.     return alltypes, ctor
  289.  
  290.  
  291.